﻿using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Net.Sockets;
using System.Text;
using TD.CodeGen.Models;

namespace Nlizard.CodeGen.Controllers
{
    public class CodeGenController : Controller
    {

        private readonly IHostingEnvironment _hostingEnvironment;

        public CodeGenController(IHostingEnvironment hostingEnvironment)
        {
            _hostingEnvironment = hostingEnvironment;
        }
        public JsonResult Index(string projectName)
        {
            try
            {
                string webRootPath = _hostingEnvironment.WebRootPath;
                string fileContent;

                string tempPath = Path.Combine(webRootPath, "temp");
                using (StreamReader reader = System.IO.File.OpenText(Path.Combine(tempPath, "project.json")))
                {
                    fileContent = reader.ReadToEnd();
                }
                ModuleInfo project = JsonConvert.DeserializeObject<ModuleInfo>(fileContent);
                if (projectName.LastIndexOf(".") > 0)
                {
                    project.KeyWord = projectName.Substring(projectName.LastIndexOf(".") + 1);
                }
                else
                {
                    project.KeyWord = projectName;
                }
                project.Name = projectName;
                if (string.IsNullOrEmpty(project.RootPath))
                {
                    project.RootPath = Path.Combine(webRootPath, "pkg");
                }

                //创建任务
                //Task task = new Task(() =>
                //{
                CreateProject(project, tempPath);
                //});
                //启动任务,并安排到当前任务队列线程中执行任务(System.Threading.Tasks.TaskScheduler)
                //task.Start();
                return Json(new { code = 1, url = "/pkg/" + project.Name + ".zip" });
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return Json(new { code = 0, msg = ex.Message });
            }

        }

        private void CreateProject(ModuleInfo project, string tempPath)
        {
            Dictionary<string, string> modules = new Dictionary<string, string>();
            string projectPath = Path.Combine(project.RootPath, project.Name);
            if (Directory.Exists(projectPath))
            {
                Directory.Delete(projectPath, true);
            }
            Directory.CreateDirectory(projectPath);

            foreach (var module in project.Dirs)
            {
                string moduleGuid = Guid.NewGuid().ToString().ToUpper();
                string moduleName = "";
                if (string.IsNullOrEmpty(module.Name))
                {
                    moduleName = project.Name;
                }
                else
                {
                    moduleName = string.Format("{0}.{1}", project.Name, module.Name);
                }
                modules.Add(moduleName, moduleGuid);
                string modulePath = Path.Combine(projectPath, moduleName);
                Directory.CreateDirectory(modulePath);
                foreach (var submodule in module.Dirs)
                {
                    string dirPath = Path.Combine(modulePath, submodule.Name);
                    Directory.CreateDirectory(dirPath);
                    if (submodule.Files != null && submodule.Files.Count > 0)
                    {
                        foreach (var item in submodule.Files)
                        {
                            string filePath = Path.Combine(dirPath, item.Name.Replace("{projectName}", project.Name));
                            string tempFilePath = Path.Combine(tempPath, item.TemPath);
                            if (item.Name.EndsWith(".cs"))
                            {
                                CreateCsFile(filePath, tempFilePath, project.KeyWord, project.Name, moduleName, moduleGuid);
                            }
                            else
                            {
                                CreateFile(filePath, tempFilePath);
                            }
                        }
                    }
                }
                foreach (var file in module.Files)
                {
                    string filePath = Path.Combine(modulePath, file.Name.Replace("{projectName}", project.Name));
                    string tempFilePath = Path.Combine(tempPath, file.TemPath);

                    if (file.Name.EndsWith(".csproj") || file.Name.Equals("launchSettings.json"))
                    {
                        CreateCSproject(filePath, tempFilePath, project.Name, moduleName, moduleGuid, modules);
                    }
                    else if (file.Name.EndsWith(".cs"))
                    {
                        CreateCsFile(filePath, tempFilePath, project.KeyWord, project.Name, moduleName, moduleGuid);
                    }
                    else if (file.Name.EndsWith(".ini") || file.Name.EndsWith(".cmd"))
                    {
                        CreateJsonFile(filePath, tempFilePath, project.Name);
                    }
                    else
                    {
                        CreateFile(filePath, tempFilePath);
                    }
                }
            }

            foreach (var file in project.Files)
            {
                string filePath = Path.Combine(projectPath, file.Name.Replace("{projectName}", project.Name));
                string tempFilePath = Path.Combine(tempPath, file.TemPath);
                CreateSln(filePath, tempFilePath, project.Name, modules);
            }

            string zipFilePath = Path.Combine(project.RootPath, project.Name + ".zip");

            ZipProject(projectPath, zipFilePath);
        }


        private void CreateCsFile(string filePath, string tempPath, string keyword, string projectName, string moduleName, string moduleGuid)
        {
            if (System.IO.File.Exists(tempPath))
            {
                string text = System.IO.File.ReadAllText(tempPath);
                if (text.Trim().Length > 0)
                {
                    text = text.Replace("$$KeyWord$$", keyword);
                    text = text.Replace("$$ProjectName$$", projectName);
                    text = text.Replace("$$ModuleName$$", moduleName);
                    text = text.Replace("$$ModuleProjectGuid$$", moduleGuid);
                    WriteAllText(filePath, text);
                }
            }
        }

        private void ZipProject(string projectPath, string zipFilePath)
        {
            if (System.IO.File.Exists(zipFilePath))
            {
                System.IO.File.Delete(zipFilePath);
            }
            ZipFile.CreateFromDirectory(projectPath, zipFilePath);
            Directory.Delete(projectPath, true);
        }

        private void CreateCSproject(string filePath, string tempPath, string projectName, string moduleName, string moduleGuid, Dictionary<string, string> modules)
        {
            if (System.IO.File.Exists(tempPath))
            {
                string text = System.IO.File.ReadAllText(tempPath);
                if (text.Trim().Length > 0)
                {
                    text = text.Replace("$$ModuleName$$", moduleName);
                    text = text.Replace("$$ModuleProjectGuid$$", moduleGuid);
                    text = text.Replace("$$ProjectName$$", projectName);
                    text = text.Replace("$$ModulePort$$", FreeTcpPort().ToString());
                    WriteAllText(filePath, text);
                }
            }
        }

        private int FreeTcpPort()
        {
            TcpListener l = new TcpListener(IPAddress.Loopback, 0);
            l.Start();
            int port = ((IPEndPoint)l.LocalEndpoint).Port;
            l.Stop();
            return port;
        }

        private void CreateFile(string filePath, string tempPath)
        {
            if (System.IO.File.Exists(tempPath))
            {
                string text = System.IO.File.ReadAllText(tempPath);
                if (text.Trim().Length > 0)
                {
                    WriteAllText(filePath, text);
                }
            }
        }

        private void CreateJsonFile(string filePath, string tempPath, string projectName)
        {
            if (System.IO.File.Exists(tempPath))
            {
                string text = System.IO.File.ReadAllText(tempPath);
                if (text.Trim().Length > 0)
                {
                    text = text.Replace("$$ProjectName$$", projectName);
                    WriteAllText(filePath, text);
                }
            }
        }

        private void CreateSln(string filePath, string tempPath, string projectName, Dictionary<string, string> modules)
        {
            if (System.IO.File.Exists(tempPath))
            {
                string text = System.IO.File.ReadAllText(tempPath);
                if (text.Trim().Length > 0)
                {
                    StringBuilder sb = new StringBuilder();
                    StringBuilder sb2 = new StringBuilder();
                    StringBuilder sb3 = new StringBuilder();
                    var index = 0;
                    foreach (var item in modules)
                    {
                        sb.Append("Project(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"" + item.Key + "\", \"" + item.Key + "\\" + item.Key + ".csproj\", \"{" + item.Value + "}\"");
                        sb.Append(Environment.NewLine);
                        sb.Append("EndProject");
                        sb.Append(Environment.NewLine);
                        sb3.Append("            {" + item.Value + "}.Debug|Any CPU.ActiveCfg = Debug|Any CPU");
                        sb3.Append(Environment.NewLine);
                        sb3.Append("            {" + item.Value + "}.Debug|Any CPU.Build.0 = Debug|Any CPU");
                        sb3.Append(Environment.NewLine);
                        sb3.Append("            {" + item.Value + "}.Release|Any CPU.ActiveCfg = Release|Any CPU");
                        sb3.Append(Environment.NewLine);
                        sb3.Append("            {" + item.Value + "}.Release|Any CPU.Build.0 = Release|Any CPU");
                        if (index < modules.Count - 1)
                        {
                            sb3.Append(Environment.NewLine);
                        }
                        index++;
                    }
                    text = text.Replace("$$Projects$$", sb.ToString());
                    text = text.Replace("$$NestedProjects$$", "SolutionGuid = {" + Guid.NewGuid().ToString().ToUpper() + "}");
                    text = text.Replace("$$ProjectConfigurationPlatforms$$", sb3.ToString());
                    WriteAllText(filePath, text);
                }
            }
        }

        private void WriteAllText(string filePath, string text)
        {
            if (System.IO.File.Exists(filePath))
            {
                System.IO.File.Delete(filePath);
            }
            using (FileStream stream = System.IO.File.Create(filePath))
            {
                using (StreamWriter writer = new StreamWriter(stream, Encoding.UTF8))
                {
                    writer.Write(text);
                }
            }
        }

    }
}